`timescale 1ns / 1ps
//////////////////////////////////////////////////////////////////////////////////
// Company: 
// Engineer: 
// 
// Create Date: 2021/04/26 20:27:24
// Design Name: 
// Module Name: Decoder
// Project Name: 
// Target Devices: 
// Tool Versions: 
// Description: 
// 
// Dependencies: 
// 
// Revision:
// Revision 0.01 - File Created
// Additional Comments:
// 
//////////////////////////////////////////////////////////////////////////////////


module Idecode32(
    //input the instruction
    input[31:0] Instruction,
    //the data from IO or Memory
    input[31:0] read_data,
    //the result calculated by ALU
    input[31:0] ALU_result,

    //from the Control signal
    input Jal,//whether it is jal or not
    input RegWrite,//turn on the write
    input RegDst, //indicate the data go to ALU or Memory,1-->ALU
    input MemtoReg,//indicate the data from ALU or Memory

    //the clock and reset
    input clock,
    input reset,

    //used in jal, pc+4 into $ra
    input[31:0] opcplus4,
    
    //the fireset op num
    output[31:0] read_data_1,
    //the second op num
    output[31:0] read_data_2, 
    //the 32-bit immediate
    output[31:0] imme_extend

);


//register file
reg[31:0] registers[0:31];
//the data to be writen into register file
reg[31:0] write_data;
//the written register number
reg[4:0] write_register_num;

//the num of read register1
wire[4:0] read_register1_num;
//the num of read register2
wire[4:0] read_register2_num;

//rd to be written in R-type
wire[4:0] rd;
//rt to be written in I-type(sw)
wire[4:0] rt;

//the immediate embedded in instruction
wire[15:0] immediate;
//the opcode in the instruction
wire[5:0] opcode;


//assign the opcode: Instruction[31:26]
assign opcode = Instruction[31:26];
//assign rs
assign read_register1_num = Instruction[25:21];
//assign rt
assign read_register2_num = Instruction[20:16];
//assign written rt in sw
assign rt = Instruction[20:16];
//assign written rd in R-type
assign rd = Instruction[15:11];
//assign the immediate value
assign immediate = Instruction[15:0];


//assign the extended immediate
//andi and ori use zero-extended immediate
wire sign;
assign sign = Instruction[15];
assign imme_extend = (opcode == 6'b001100 || opcode == 6'b001101) ? {{16{1'b0}},immediate} : {{16{sign}},immediate};


//assign read_data_1 and read_data_2
assign read_data_1 = registers[read_register1_num];
assign read_data_2 = registers[read_register2_num];


//determine the write_register_num
always @(*) 
begin
//if the RegWrite is on
    if(RegWrite == 1)
    begin
        //if the instruction is jal, write to $ra(31)
        if(opcode == 6'b000011 && Jal == 1'b1)
        begin
            write_register_num = 5'b11111;
        end
        //if the instruction is R-type,the num is rd
        else if(opcode == 6'b0 && RegDst == 1'b1)
        begin
            write_register_num = rd;
        end
        //if the instuction is sw, the num is rt
        else begin
            write_register_num = rt;
        end
    end    
end



//determine the write data
always @(*) 
begin
    //if the instruction is jal
    if(opcode == 6'b000011 && Jal == 1'b1)
    begin
        write_data = opcplus4;
    end
    //if the write data is from memory or IO
    else if(MemtoReg == 1'b1)
    begin
        write_data = read_data;
    end
    //if the write data is from ALU
    else begin
        write_data = ALU_result;
    end
    
end


//use sequential circuit to initialize the register file
integer i;
always @(posedge clock) 
begin
    //if the reset is on,initialize all the register to 0
    if(reset == 1'b1)
    begin
        for(i=0;i<32;i=i+1) registers[i] <= 0;
    end
    // if the RegWrite is on
    else if(RegWrite == 1)
    begin
        //the $zero cannot be written
        if(write_register_num == 0)
        begin
        end
        else begin
            registers[write_register_num] <= write_data;
        end
    end
end

endmodule
